package com.imooc.miaosha.exception;

import com.alibaba.fastjson.JSONObject;
import com.imooc.miaosha.pojo.ApiResultTo;
import com.imooc.miaosha.pojo.CodeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/*@Controller的增强器，可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理。
* 我感觉这个很像一个拦截器，拦截所有@RequestMapping注解的方法。
* 感觉用拦截器这个描述不是很好，因为拦截器一般是对请求（request）的拦截，而对响应（response）是没有拦截这么一个说法的
* 参考：https://blog.csdn.net/qq_21492635/article/details/89381204
* 这篇文章底下的评论很有收获：
* 我是这么理解的，如果不对，欢迎指出。如果一个异常，在service层没有被catch到，那么，这个异常就传递到了controller层，
* 如果controller不做处理，页面看到的就是500了。全局异常处理，针对的是这种情况：当异常不能被catch的时候，避免给用户展示
* 500界面，在controller层做的统一处理，跳转到我们自定义的错误页面，或者返回自定义的error信息。
*
* 看了这个理解发现自己对异常处理中的throws xxxException的理解不够深刻。`throws`是向该方法或类的调用者抛出，
* 那么这个调用者就得处理，要么`try catch`，要么继续甩锅（即再throw到它的调用者）。
* */
@ControllerAdvice
@ResponseBody//表示返回值作为返回值体
public class GlobalExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    @ExceptionHandler(value = Exception.class)//表示拦截所 有的异常，因为所有异常都是Exception类的子类
    public ApiResultTo<?> exceptionHandler(HttpServletRequest request,Exception e){
        e.printStackTrace();
        if (e instanceof GlobalException){
            GlobalException ex = (GlobalException)e;
            return ApiResultTo.buildFailed(ex.getCodeMsg());
        }
        else if (e instanceof BindException){//进行参数校验报错，注意导包别导错了
            BindException bindException = (BindException)e;
            List<ObjectError> errors = bindException.getAllErrors();//因为错误可能不只一个
            ObjectError error = errors.get(0);
            String msg = error.getDefaultMessage();
            return ApiResultTo.buildFailed(CodeMsg.BIND_ERROR.fillArgs(e.getMessage()));
        }
        return ApiResultTo.buildFailed(CodeMsg.SERVER_ERROR.fillArgs(e.getMessage()));
    }
}
